﻿using System;
using System.Collections;
using System.Collections.Generic;
using System.Diagnostics;
using System.Threading;
using System.Windows.Forms;
using FFACETools;
using XMLManager;

namespace SMN
{
    public partial class Form1 : Form
    {
        FFACE _FFACE { get; set; }

        private List<String> _Avatars = new List<String>();
        private Hashtable _Staves = new Hashtable();
        private Hashtable __Staves = new Hashtable();
        private DateTime _StartDate = DateTime.Now;
        private DateTime _EndDate = DateTime.Now;
        private String _Spell = String.Empty;
        private Hashtable _Equivalent = new Hashtable();
        private bool _Debug = false;

        private delegate void DelegateModifyHpMp();
        private delegate void DelegateSMNSkill();
        DelegateSMNSkill dlgSMNSkill;
        DelegateModifyHpMp dlgModifyHpMp;

        public Form1(bool dbg)
        {
            _Debug = dbg;
            InitializeComponent();
            Process[] Pol = Process.GetProcessesByName("pol");
            if (Pol.Length < 1)
            {
                if (!_Debug)
                {
                    if (MessageBox.Show("FFXI Is not running, application will close.", "Error", MessageBoxButtons.OK, MessageBoxIcon.Error) == DialogResult.OK)
                    {
                        System.Environment.Exit(0);
                    }
                }
                else
                {
                    MessageBox.Show("Entering debugging mode.", "Debugging", MessageBoxButtons.OK, MessageBoxIcon.Information);
                    this.Modify();
                }
            }

            try
            {
                if (!_Debug)
                {
                    this.StartProcess(Pol[0].Id);
                    this.AsName();
                    this.Modify();
                }
                else
                {
                    this.lbName.Text = "Debug Session";
                }
            }
            catch (Exception Ex)
            {
                MessageBox.Show("Error: " + Ex.Message, "Error", MessageBoxButtons.OK, MessageBoxIcon.Error);
            }
        }

        private void Form1_Load(object sender, EventArgs e)
        {
            this.FillStaves();
            this.LoopAvatarCheckBoxes();
            this.LoopSpiritCheckBoxes();
            this.LoopStavesCheckBoxes();
        }

        private void StartProcess(int ProcessId)
        {
            _FFACE = new FFACE(ProcessId);
        }

        private void ModifyHpMp()
        {
            if (!_Debug)
            {
                if (this.lbMP.InvokeRequired || this.lbHP.InvokeRequired)
                {
                    this.Invoke(new DelegateModifyHpMp(ModifyHpMp));
                }
                else
                {
                    this.lbMP.Text = _FFACE.Player.MPMax.ToString() + "/" + _FFACE.Player.MPCurrent.ToString() + " " + _FFACE.Player.MPPCurrent.ToString() + "%";
                    this.lbHP.Text = _FFACE.Player.HPMax.ToString() + "/" + _FFACE.Player.HPCurrent.ToString() + " " + _FFACE.Player.HPPCurrent.ToString() + "%";
                }
            }
            else
            {
                if (this.lbMP.InvokeRequired)
                {
                    this.Invoke(dlgModifyHpMp);
                }
                else
                {
                    this.lbMP.Text = _debugMP.ToString();
                }
            }
        }

        private void AsName()
        {
            this.lbName.Text = _FFACE.Player.Name;
        }

        private void SMNSkill()
        {
            if (this.lbSkill.InvokeRequired)
            {
                this.Invoke(new DelegateSMNSkill(this.SMNSkill));
            }
            else
            {
                if (!_Debug)
                {
                    this.lbSkill.Text = _FFACE.Player.GetMagicSkillDetails(MagicSkill.Summoning).Level.ToString();
                    if (!_FFACE.Player.GetMagicSkillDetails(MagicSkill.Summoning).Capped)
                    {
                        this.lbStatus.Text = "Skill not capped.";
                    }
                    else
                    {
                        this.lbStatus.Text = "Skill is capped, Program has finished.";
                        this.enter = false;
                    }
                }
                else
                {
                    this.lbSkill.Text = "Debug FakeMp: " + _debugMP.ToString();
                }
            }
        }

        private void LoopAvatarCheckBoxes()
        {
            foreach (Control Ctrl in this.groupBox2.Controls)
            {
                if (Ctrl is CheckBox)
                {
                    CheckBox cb = (CheckBox)Ctrl;
                    if (cb.CheckState == CheckState.Checked)
                    {
                        if (!_Avatars.Contains(cb.Text))
                        {
                            this._Avatars.Add(cb.Text);
                        }
                    }
                }
            }
        }

        private void LoopSpiritCheckBoxes()
        {
            String Spirit = " Spirit";
            foreach (Control Ctrl in this.groupBox3.Controls)
            {
                if (Ctrl is CheckBox)
                {
                    CheckBox cb = (CheckBox)Ctrl;
                    if (cb.CheckState == CheckState.Checked)
                    {
                        if (!_Avatars.Contains(cb.Text + Spirit))
                        {
                            this._Avatars.Add(cb.Text + Spirit);
                        }
                    }
                }
            }
        }

        private void LoopStavesCheckBoxes()
        {
            foreach (Control Ctrl in this.groupBox5.Controls)
            {
                if (Ctrl is CheckBox)
                {
                    CheckBox Cb = (CheckBox)Ctrl;
                    if (Cb.CheckState == CheckState.Checked)
                    {
                        if (Cb.Name.Length == 5)
                        {
                            String[] Name = { Cb.Name.Substring(0, 1), Cb.Name.Substring(1, 2) };
                            this.AddStaff(Name);
                        }
                        else if (Cb.Name.Length == 6)
                        {
                            String[] Name = { Cb.Name.Substring(0, 2), Cb.Name.Substring(2, 2) };
                            this.AddStaff(Name);
                        }
                    }
                }
            }
        }

        private void checkBox1_CheckedChanged(object sender, EventArgs e)
        {
            CheckBox cb = (CheckBox)sender;
            if (cb.CheckState == CheckState.Checked)
            {
                if (!this._Avatars.Contains(cb.Text))
                {
                    this._Avatars.Add(cb.Text);
                }
            }
            else if (cb.CheckState == CheckState.Unchecked)
            {
                if(this._Avatars.Contains(cb.Text))
                {
                    this._Avatars.Remove(cb.Text);
                }
            }
        }

        private void checkBox26_CheckedChanged(object sender, EventArgs e)
        {
            CheckBox cb = (CheckBox)sender;
            String Spirit = " Spirit";
            if (cb.CheckState == CheckState.Checked)
            {
                if (!this._Avatars.Contains(cb.Text + Spirit))
                {
                    this._Avatars.Add(cb.Text + Spirit);
                }
            }
            else if (cb.CheckState == CheckState.Unchecked)
            {
                if (this._Avatars.Contains(cb.Text + Spirit))
                {
                    this._Avatars.Remove(cb.Text + Spirit);
                }
            }
        }

        private void Form1_FormClosing(object sender, FormClosingEventArgs e)
        {
            SMN.Properties.Settings.Default.Save();
        }

        private void FillStaves()
        {
            Hashtable NQStaves = new Hashtable();
            NQStaves.Add("L", "Light Staff");
            NQStaves.Add("D", "Dark Staff");
            NQStaves.Add("W", "Water Staff");
            NQStaves.Add("E", "Earth Staff");
            NQStaves.Add("I", "Ice Staff");
            NQStaves.Add("Wi", "Wind Staff");
            NQStaves.Add("F", "Fire Staff");
            NQStaves.Add("T", "Thunder Staff");

            Hashtable HQStaves = new Hashtable();
            HQStaves.Add("L", "HLight Staff");
            HQStaves.Add("D", "HDark Staff");
            HQStaves.Add("W", "HWater Staff");
            HQStaves.Add("E", "HEarth Staff");
            HQStaves.Add("I", "HIce Staff");
            HQStaves.Add("Wi", "HWind Staff");
            HQStaves.Add("F", "HFire Staff");
            HQStaves.Add("T", "HThunder Staff");

            this._Staves.Add("NQ", NQStaves);
            this._Staves.Add("HQ", HQStaves);

            this._Equivalent.Add("Carbuncle", "L");
            this._Equivalent.Add("Fenrir", "D");
            this._Equivalent.Add("Titan", "E");
            this._Equivalent.Add("Leviathan", "W");
            this._Equivalent.Add("Shiva", "I");
            this._Equivalent.Add("Garuda", "Wi");
            this._Equivalent.Add("Ifrit", "F");
            this._Equivalent.Add("Ramuh", "T");
            this._Equivalent.Add("Diabolos", "D");
            this._Equivalent.Add("Light Spirit", "L");
            this._Equivalent.Add("Dark Spirit", "D");
            this._Equivalent.Add("Earth Spirit", "E");
            this._Equivalent.Add("Water Spirit", "W");
            this._Equivalent.Add("Ice Spirit", "I");
            this._Equivalent.Add("Wind Spirit", "Wi");
            this._Equivalent.Add("Fire Spirit", "F");
            this._Equivalent.Add("Thunder Spirit", "T");
        }

        private void cbLNQ_CheckedChanged(object sender, EventArgs e)
        {
            //if (!((CheckBox)sender).Checked) { return; }

            String SName = ((CheckBox)sender).Name;
            String SQName = string.Empty;
            String[] SSName = new String[2];
            String[] SSQName = new String[2];
            int NameLenght = SName.Length;

            if (SName.Contains("N"))
            {
                SQName = SName.Replace("N", "H");
            }
            else if (SName.Contains("H"))
            {
                SQName = SName.Replace("H", "N");
            }

            ((CheckBox)this.groupBox5.Controls[SQName]).Checked = !((CheckBox)sender).Checked;

            SName = SName.Remove(0, 2);
            SQName = SQName.Remove(0, 2);

            if (NameLenght == 5)
            {
                SSName[0] = SName.Substring(0, 1);
                SSName[1] = SName.Substring(1, 2);
                SSQName[0] = SQName.Substring(0, 1);
                SSQName[1] = SQName.Substring(1, 2);
            }
            else if (NameLenght == 6)
            {
                SSName[0] = SName.Substring(0, 2);
                SSName[1] = SName.Substring(2, 2);
                SSQName[0] = SQName.Substring(0, 2);
                SSQName[1] = SQName.Substring(2, 2);
            }

            this.AddRemove(SSName, SSQName);
        }

        private String ExtractSSName(String[] Name)
        {
            return ((Hashtable)this._Staves[Name[1]])[Name[0]].ToString();
        }

        private void AddStaff(String[] Name)
        {
            if (this._Staves.Contains(Name[1]))
            {
                this.__Staves.Add(Name[0], this.ExtractSSName(Name));
            }
        }

        private void RemoveStaff(String[] Name)
        {
            if (this.__Staves.Contains(Name[0]))
            {
                this.__Staves.Remove(Name[0]);
            }
        }

        private void AddRemove(String[] Name, String[] SName)
        {
            this.RemoveStaff(SName);
            this.AddStaff(Name);
        }

        private void dateTimePicker1_ValueChanged(object sender, EventArgs e)
        {
            _StartDate = ((DateTimePicker)sender).Value;
        }

        private void dateTimePicker2_ValueChanged(object sender, EventArgs e)
        {
            _EndDate = ((DateTimePicker)sender).Value;
        }

        private void closeToolStripMenuItem_Click(object sender, EventArgs e)
        {
            this.Close();
        }

        private void button1_Click(object sender, EventArgs e)
        {
            if (!enter)
            {
                enter = true;
                ((Button)sender).Text = "Stop";
                this.Init();
            }
            else
            {
                enter = false;
                ((Button)sender).Text = "Start";
            }
        }

        private bool Casting = false;
        private bool Resting = false;
        private bool enter = false;

        private void Init()
        {
            if (!enter)
            {
                if (this.cbLogoff.Checked)
                {
                    this.PrintCmd("/logoff");
                }
            }
            else if ((_EndDate > DateTime.Now) && enter && this.cbUseTimer.Checked)
            {
                if (!ThreadPool.QueueUserWorkItem(new WaitCallback(this.Start)))
                {
                    MessageBox.Show("Sistem error", "Error", MessageBoxButtons.OK, MessageBoxIcon.Error);
                }
            }
            else if (!this.cbUseTimer.Checked && enter)
            {
                if (!ThreadPool.QueueUserWorkItem(new WaitCallback(this.Start)))
                {
                    MessageBox.Show("Sistem error", "Error", MessageBoxButtons.OK, MessageBoxIcon.Error);
                }
            }
            else
            {
                if (this.cbLogoff.Checked)
                {
                    this.PrintCmd("/logoff");
                }
            }
        }

        private int _debugMP = 35;
        private void Start(Object obj)
        {
            if (!_Debug)
            {
                if (_FFACE.Player.MPCurrent < 30 && !Resting && enter)
                {
                    this.StartResting();
                }
                if (_FFACE.Player.MPPCurrent == 100 && !Casting && enter)
                {
                    this.StartCasting();
                }
                else
                {
                    this.StartResting();
                }
            }
            else
            {
                if (_debugMP < 30 && !Resting && enter)
                {
                    this.StartResting();
                }
                if (_debugMP == 35 && !Casting && enter)
                {
                    this.StartCasting();
                }
            }
            this.Init();
        }

        private void StartResting()
        {
            Resting = true;
            Casting = !Resting;
            if (!_Debug)
            {
                this.RestingActions(_FFACE.Player.Status, _FFACE.Player.MPCurrent, _FFACE.Player.MPMax);
            }
            else
            {
                this.RestingActions(Status.Standing, _debugMP, 35);
            }
        }

        private void RestingActions(Status St, int MPCurrent, int MPMax)
        {
            if (St != Status.Healing)
            {
                this.PrintCmd("/heal");
                Thread.Sleep(1000);
            }

            while (MPCurrent < MPMax)
            {
                if (!enter) { break; }
                Thread.Sleep(1000);
                if (_Debug)
                {
                    MPCurrent++;
                    _debugMP = MPCurrent;
                }
                else
                {
                    MPCurrent = _FFACE.Player.MPCurrent;
                }
                this.Modify();
            }
        }

        private void StartCasting()
        {
            Casting = true;
            Resting = !Casting;

            if (!_Debug)
            {
                this.CastingActions(_FFACE.Player.Status, _FFACE.Player.MPPCurrent);
            }
            else
            {
                this.CastingActions(Status.Standing, _debugMP, 0);
            }
        }

        private void CastingActions(Status st, int MPCurrent)
        {
            this.CastingActions(st, MPCurrent, 0);
        }

        private void CastingActions(Status st, int MPCurrent, int CastPercentEx)
        {
            bool HasAvatar = false;
            if (st == Status.Healing)
            {
                this.PrintCmd("/heal");
                Thread.Sleep(1000);
            }

            while (MPCurrent > 20)
            {
                if (_Avatars.Count == 0) { break; }
                foreach (String Spell in _Avatars)
                {
                    if (MPCurrent < 20) { break; }

                    this.PrintCmd("/ma \"" + Spell + "\" <me>", Spell);

                    if (!_Debug)
                    {
                        while (_FFACE.Player.CastPercentEx < 100) { Thread.Sleep(500); }
                        HasAvatar = true;
                    }
                    else
                    {
                        while (CastPercentEx < 100) { Thread.Sleep(20); CastPercentEx++; }
                        CastPercentEx = 0;
                        Thread.Sleep(1000);
                    }

                    if (HasAvatar)
                    {
                        this.PrintCmd("/pet \"Release\" <me>");
                        HasAvatar = false;
                        Thread.Sleep(1000);
                    }

                    if (_Debug)
                    {
                        MPCurrent--;
                        _debugMP = MPCurrent;
                    }
                    else
                    {
                        MPCurrent = _FFACE.Player.MPCurrent;
                    }

                    this.Modify();

                    if (!enter) { break; }
                }
            }
        }

        private void PrintCmd(String Cmd)
        {
            if (!_Debug) { _FFACE.Windower.SendString(Cmd); }
            this.lbCmd.Text = Cmd;
            Thread.Sleep(1000);
        }

        private void PrintCmd(String Cmd, String Spell)
        {
            this.PrintCmd(Cmd);
            if (this.__Staves.ContainsKey(this._Equivalent[Spell]))
            {
                String CmdStaff = "/equip main \"" + this.__Staves[this._Equivalent[Spell]] + "\"";
                this.PrintCmd(CmdStaff);
            }
        }

        private void Modify()
        {
            this.ModifyHpMp();
            this.SMNSkill();
        }

        private String OriginalText = String.Empty;
        private void toolStripTextBox1_Click(object sender, EventArgs e)
        {
            
        }

        private void toolStripTextBox1_TextChanged(object sender, EventArgs e)
        {
            
        }

        private void cbAllAvatars_CheckedChanged(object sender, EventArgs e)
        {
            foreach (Control ctrl in this.groupBox2.Controls)
            {
                if (ctrl is CheckBox)
                {
                    ((CheckBox)ctrl).Checked = ((CheckBox)sender).Checked;
                }
            }
        }

        private void cbAllSpirits_CheckedChanged(object sender, EventArgs e)
        {
            foreach (Control ctrl in this.groupBox3.Controls)
            {
                if (ctrl is CheckBox)
                {
                    ((CheckBox)ctrl).Checked = ((CheckBox)sender).Checked;
                }
            }
        }

        private void aToolStripMenuItem_Click(object sender, EventArgs e)
        {
            About ab = new About();
            if (ab.ShowDialog() == DialogResult.OK)
            { }
        }

        private void testXMLToolStripMenuItem_Click(object sender, EventArgs e)
        {
            XMLM m = new XMLM("UserData.xml");
        }
    }
}
